package com.tsd.core.utils;

import cn.hutool.core.bean.BeanUtil;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToDoubleFunction;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @ClassName: ListUtil
 * @Description: 列表处理工具类
 * @Author: Luoyc
 * @Date: 2020/6/12 10:53
 * @Version: 1.0
 */
public class ListUtil {
    /**
     * 满足要求的第一个数据位置
     *
     * @param list
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> int indexOf(List<T> list, Predicate<? super T> predicate) {
        if (list == null) {
            return -1;
        }
        return IntStream.range(0, list.size())
                .filter(ix -> predicate.test(list.get(ix)))
                .findFirst().orElse(-1);
    }

    /**
     * 返回满足需求的第一个对象
     *
     * @param list
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> T get(List<T> list, Predicate<? super T> predicate) {
        int index = indexOf(list, predicate);
        if (index != -1) {
            return list.get(index);
        }
        return null;
    }

    /**
     * 返回所提供的比较器的最小值对应的对象
     *
     * @param list
     * @param comparator
     * @param <T>
     * @return
     */
    public static <T> T min(List<T> list, Comparator<T> comparator) {
        return list.parallelStream().min(comparator).orElse(null);
    }

    /**
     * 返回所提供的比较器的最大值对应的对象
     *
     * @param list
     * @param comparator
     * @param <T>
     * @return
     */
    public static <T> T max(List<T> list, Comparator<T> comparator) {
        return list.parallelStream().max(comparator).orElse(null);
    }

    /**
     * 返回满足条件的对象列表
     *
     * @param list
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> List<T> filter(List<T> list, Predicate<? super T> predicate) {
        if (list == null) {
            return new ArrayList<>();
        }
        return list.parallelStream().filter(predicate).collect(Collectors.toList());
    }

    /**
     * 返回满足条件的对象列表
     *
     * @param list
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> List<T> filter(Set<T> list, Predicate<? super T> predicate) {
        if (list == null) {
            return new ArrayList<>();
        }
        return list.parallelStream().filter(predicate).collect(Collectors.toList());
    }

    /**
     * 返回列表的对象个数，列表为空时返回0
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> Integer count(List<T> list) {
        if (list == null) {
            return 0;
        }
        return list.size();
//        long count = list.parallelStream().count();
//        return Long.valueOf(count).intValue();
    }

    /**
     * 返回满足要求的对象个数
     *
     * @param list
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> Integer filterCount(List<T> list, Predicate<? super T> predicate) {
        if (list == null) {
            return 0;
        }
        return count(filter(list, predicate));
    }

    /**
     * 对列表内对象的某种数值进行合计，返回其结果
     * double totalReturn = ListUtil.sum(filter, JxcBuyReturnBillDetailExt::getQty);
     *
     * @param list
     * @param mapper
     * @param <T>
     * @return
     */
    public static <T> double sum(List<T> list, ToDoubleFunction<? super T> mapper) {
        if (list == null) {
            return 0D;
        }
        return list.parallelStream().mapToDouble(mapper).sum();
    }

    /**
     * 对列表先过滤，然后再统计某种数据的合计结果
     *
     * @param list
     * @param predicate
     * @param mapper
     * @param <T>
     * @return
     */
    public static <T> double filterSum(List<T> list, Predicate<? super T> predicate, ToDoubleFunction<? super T> mapper) {
        return sum(filter(list, predicate), mapper);
    }

    /**
     * 根据比较器对列表进行排序，返回新列表
     *
     * @param list
     * @param comparator
     * @param <T>
     * @return
     */
    public static <T> List<T> sorted(List<T> list, Comparator<? super T> comparator) {
        if (list == null) {
            return new ArrayList<>();
        }
        return list.parallelStream().sorted(comparator).collect(Collectors.toList());
    }

    /**
     * 根据过滤条件和比较器对列表进行过滤和排序，返回新列表
     *
     * @param list
     * @param predicate
     * @param comparator
     * @param <T>
     * @return
     */
    public static <T> List<T> filterSorted(List<T> list, Predicate<? super T> predicate, Comparator<? super T> comparator) {
        return sorted(filter(list, predicate), comparator);
    }

    /**
     * 返回是否存在满足条件的对象，列表为空时返回false
     *
     * @param list
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> boolean anyMatch(List<T> list, Predicate<? super T> predicate) {
        if (list == null) {
            return false;
        }
        return list.parallelStream().anyMatch(predicate);
    }

    /**
     * 将List里面每个对象的某个属性组成List返回，新list里面的对象不重复
     * 例如：List<Long> idList = ListUtil.map(itemExtList, AssetsFeeFormulaItemExt::getId);
     *
     * @param list
     * @param mapper
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> map(List<T> list, Function<? super T, ? extends R> mapper) {
        if (list == null) {
            return new ArrayList<>();
        }
        return list.parallelStream().map(mapper).distinct().collect(Collectors.toList());
    }

    /**
     * 将List里面每个对象的某个属性组成List返回，新list里面的对象可以不重复
     * List<String> calList = ListUtil.mapNoDistinct(itemVoList, t -> {
     * if (!HlpUtils.isEmpty(t.getId())) {
     * return "params." + t.getValue();
     * }
     * return t.getValue();
     * });
     *
     * @param list
     * @param mapper
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> mapNoDistinct(List<T> list, Function<? super T, ? extends R> mapper) {
        if (list == null) {
            return new ArrayList<>();
        }
        return list.parallelStream().map(mapper).collect(Collectors.toList());
    }

    /**
     * 将List的对象先进行过滤，然后再将结果的某个属性组成List返回，新list里面的对象不重复
     *
     * @param list
     * @param predicate
     * @param mapper
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> filterMap(List<T> list, Predicate<? super T> predicate, Function<? super T, ? extends R> mapper) {
        return map(filter(list, predicate), mapper);
    }

    /**
     * 对列表内对象进行逐个执行action处理
     *
     * @param list
     * @param action
     * @param <T>
     */
    public static <T> void forEach(List<T> list, Consumer<? super T> action) {
        list.parallelStream().forEach(action);
    }

    /**
     * 将一个列表分为多个列表，每个列表内对象的最大数量为指定的大小
     *
     * @param list
     * @param size
     * @param <T>
     * @return
     */
    public static <T> List<List<T>> split(List<T> list, int size) {
        List<List<T>> resultList = new ArrayList<>();
        if (!HlpUtils.isEmptyList(list)) {
            List<T> itemList = new ArrayList<>();
            for (T data : list) {
                if (itemList.size() == size) {
                    resultList.add(itemList);
                    itemList = new ArrayList<>();
                }
                itemList.add(data);
            }
            if (!HlpUtils.isEmptyList(itemList)) {
                resultList.add(itemList);
            }
        }
        return resultList;
    }

    /**
     * 获取列表的中间对象，如果列表的长度是偶数，则取中间两个对象
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> List<T> middleList(List<T> list) {
        List<T> resultList = new ArrayList<>();
        int size = list.size();
        int middle = size / 2;
        if (size % 2 == 0) {
            resultList.add(list.get(middle - 1));
        }
        resultList.add(list.get(middle));
        return resultList;
    }

    /**
     * 复制数组
     *
     * @param list
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> copyList(List<T> list, Class<T> clazz) {
        return map(list, t -> BeanUtil.copyProperties(t, clazz));
    }

    /**
     * 过滤并复制数组
     *
     * @param list
     * @param predicate
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> filterCopy(List<T> list, Predicate<? super T> predicate, Class<T> clazz) {
        return copyList(filter(list, predicate), clazz);
    }
}
